#include "ccan.h"
#include <cstring>
#include <chrono>
#include <thread>
#include "controlcan/controlcan.h"
using namespace std;
using namespace rtbus;
namespace rtbus {
class CCanDeviceHost;
}
static std::shared_ptr<rtbus::CCanDeviceHost> can_host;
class rtbus::CCanDeviceHost
{
public:
    static std::shared_ptr<CCanDeviceHost> get()
    {
        if (!can_host.get())
        {
            can_host = make_shared<CCanDeviceHost>();
            can_host->open();
            return can_host;
        }
        return can_host;
    }
    ~CCanDeviceHost()
    {
        if (is_opened)
        {
            VCI_CloseDevice(VCI_USBCAN2, 0);
            VCI_CloseDevice(VCI_USBCAN2, 1);
        }
    }
    int open()
    {
        VCI_UsbDeviceReset(VCI_USBCAN2, 0, 0);
        // VCI_UsbDeviceReset(VCI_USBCAN2, 1, 0);
        this_thread::sleep_for(chrono::seconds(2));
        VCI_OpenDevice(VCI_USBCAN2, 0, 0);
        VCI_OpenDevice(VCI_USBCAN2, 1, 0);

        is_opened = true;
        return 0;
    }

    CCanDeviceHost() : is_opened(false) {}
    bool is_opened;
};

CCan::CCan()
{
    cfg_.dev_id = 0;
    cfg_.can_id = 0;
    cfg_.adapter_name = "";
}
CCan::~CCan() {}

int CCan::load_cfg(Config& cfg)
{
    cfg_ = cfg;
    return 0;
}

int CCan::active()
{
    CCanDeviceHost::get();

    VCI_ResetCAN(VCI_USBCAN2, cfg_.dev_id, cfg_.can_id);
    VCI_INIT_CONFIG config;
    /* init can device configure structure*/
    /* recv Data ID */
    config.AccCode = 0;
    /* no message will be masked */
    config.AccMask = 0xFFFFFFFF;
    /* recv all message */
    config.Filter = 1;
    /*
		  baudrate:1000K
		  Timing0: 0x00
		  Timing1: 0x14
		*/
    config.Timing0 = 0x00;
    config.Timing1 = 0x14;
    /* Normal mode */
    config.Mode = 0;

    if (VCI_InitCAN(VCI_USBCAN2, cfg_.dev_id, cfg_.can_id, &config) != 1)
    {
        return -1;
    }
    if (VCI_StartCAN(VCI_USBCAN2, cfg_.dev_id, cfg_.can_id) != 1)
    {
        return -1;
    }
    return 0;
}
int CCan::deactive()
{
    VCI_ResetCAN(VCI_USBCAN2, cfg_.dev_id, cfg_.can_id);
    return 0;
}

int CCan::send(FrameData* frame, size_t cnt)
{
    const size_t MAX_TX_CNT = 50;
    VCI_CAN_OBJ msg[MAX_TX_CNT];
    int max_send_cnt = cnt < MAX_TX_CNT ? cnt : MAX_TX_CNT;
    for (int i = 0; i < max_send_cnt; i++)
    {
        msg[i].ID = frame[i].id;
        msg[i].ExternFlag = frame[i].id > 0xffff;
        msg[i].RemoteFlag = 0;
        msg[i].SendType = 0;
        msg[i].DataLen = frame[i].dlc;
        memcpy(msg[i].Data, frame[i].data, frame[i].dlc);
    }

    return VCI_Transmit(VCI_USBCAN2, cfg_.dev_id, cfg_.can_id, msg, max_send_cnt);
}
int CCan::recv(FrameData* frame, size_t cnt)
{
    const size_t MAX_RX_CNT = 100;
    VCI_CAN_OBJ msg[MAX_RX_CNT];
    int max_recv_len = cnt < MAX_RX_CNT ? cnt : MAX_RX_CNT;
    int recvLen = VCI_Receive(VCI_USBCAN2, cfg_.dev_id, cfg_.can_id, msg, max_recv_len, -1);
    for (int i = 0; i < recvLen; i++)
    {
        frame[i].id = msg[i].ID;
        frame[i].dlc = msg[i].DataLen;
        memcpy(frame[i].data, msg[i].Data, msg[i].DataLen);
    }
    return recvLen;
}